<template>
  <a-modal v-model:open="open" :title="modelTitle" centered :after-close="reset" :confirm-loading="confirmLoading" @ok="onOk">
    <a-form ref="formRef" :model="formState" :rules="rules" layout="vertical">
      <a-form-item name="imageName" label="镜像名称">
        <g-input v-model:value="formState.imageName" :search="false" placeholder="请输入镜像名称" :maxlength="200" />
      </a-form-item>
      <!-- 编辑时不展示的内容 -->
      <template v-if="!formState.id">
        <a-form-item name="buildType" label="创建方式">
          <a-radio-group v-model:value="formState.buildType">
            <a-radio :value="1">Docker镜像导入</a-radio>
            <a-radio :value="2">根据Dockerfile构建</a-radio>
          </a-radio-group>
        </a-form-item>
        <a-form-item
          v-if="formState.buildType === 2"
          name="dockerFileUrlSign"
          label="镜像文件"
          :rules="[{ required: formState.buildType === 2, message: '请上传镜像文件' }]"
        >
          <a-upload
            v-model:file-list="fileList"
            class="file-upload"
            :max-count="1"
            :custom-request="customRequest"
            :accept="'.zip'"
            @remove="onRemove"
          >
            <a-button type="text" size="small" style="padding: 0" class="icon-with-btn btn-mini upload-btn">
              <i class="iconfont icon-upload-line"></i>
              上传
            </a-button>
          </a-upload>
        </a-form-item>
        <a-form-item
          v-if="formState.buildType === 1"
          name="repositoryId"
          label="仓库"
          :rules="[{ required: formState.buildType === 1, trigger: 'change', message: '请选择仓库' }]"
        >
          <a-select
            v-model:value="formState.repositoryId"
            :options="repositoryOptions"
            placeholder="请选择仓库"
            :loading="repositoryLoading"
          />
        </a-form-item>
        <a-form-item
          v-if="formState.buildType === 1"
          name="importImageTag"
          label="镜像地址"
          :rules="[{ required: formState.buildType === 1, trigger: 'change', message: '请输入镜像地址' }]"
        >
          <g-input v-model:value="formState.importImageTag" :search="false" placeholder="请输入镜像地址" :maxlength="200" />
        </a-form-item>
        <a-form-item name="frame" label="框架">
          <g-input v-model:value="formState.frame" :search="false" placeholder="请输入框架" />
        </a-form-item>
      </template>
      <a-form-item name="description" label="描述">
        <a-textarea v-model:value="formState.description" v-trim class="h-88" placeholder="请输入描述" :maxlength="200" show-count />
      </a-form-item>
    </a-form>
  </a-modal>
</template>

<script lang="ts" setup>
  import type { FormInstance } from 'ant-design-vue'
  import { message } from 'ant-design-vue'
  import type { Rule } from 'ant-design-vue/es/form'
  import { axios, cloneDeep, debounce } from 'g6-fn'
  import { computed, ref } from 'vue'
  import { useRequest } from 'vue-request'

  import { mirrorManageApi } from '@/services/api'
  import { regex, validateBitLen, validateDirName } from '@/utils'

  import { RepositoryType } from '../../types/index'

  export interface Props {
    afterCloseFn?: () => void
  }

  const props = withDefaults(defineProps<Props>(), {
    afterCloseFn: () => {}
  })

  interface FormState {
    id?: string
    imageName: string
    buildType: number
    dockerFileUrlSign?: string
    repositoryId?: string
    importImageTag?: string
    frame: string
    description: string
  }

  const open = ref(false)
  const modelTitle = computed(() => `${formState.value.id ? '编辑' : '创建'}镜像`)
  const formRef = ref<FormInstance>()
  const formState = ref<FormState>({
    id: '',
    imageName: '',
    buildType: 1,
    repositoryId: 'open',
    frame: '',
    description: ''
  })

  const rules: Record<string, Rule[]> = {
    imageName: [
      { required: true, trigger: 'change', message: '请输入镜像名称' },
      { validator: validateDirName() },
      { validator: validateBitLen(200), trigger: 'change' }
    ],
    buildType: [{ required: true, trigger: 'change', message: '请选择创建方式' }],
    frame: [{ required: true, trigger: 'change', message: '请输入框架' }]
  }

  const fileList = ref([])
  let source: any
  const checkFile = (file: any) => {
    return new Promise<void>((resolve, reject) => {
      setTimeout(() => {
        if (file.type !== 'application/zip' && file.type !== 'application/x-zip-compressed') {
          reject('仅支持zip格式')
        }
        if (!regex.dirName.test(file.name)) {
          reject('文件名称不能包含\\ / : * ? " < > | ')
        }
        const isNameValid = new TextEncoder().encode(file.name).length <= 200
        if (!isNameValid) {
          reject('文件名超出长度')
        }
        const isLt100MB = file.size / 1024 / 1024 < 100
        if (!isLt100MB) {
          reject('文件大小不能超过100MB')
        }
        resolve()
      }, 0)
    })
  }
  const customRequest = async (data: { file: any; onProgress?: any; onSuccess?: any; onError?: any }) => {
    const { file, onProgress, onError, onSuccess } = data
    formState.value.dockerFileUrlSign = 'uploading'
    try {
      await checkFile(file)
    } catch (error: any) {
      onError(file, error)
      formState.value.dockerFileUrlSign = ''
      return
    }
    try {
      let CancelToken = axios.CancelToken
      source = CancelToken.source()
      const config = {
        timeout: 300000, //设置超时时长
        onUploadProgress: (Progress: { loaded: number; total: number }) => {
          let percents = Math.round((Progress.loaded * 100) / Progress.total)
          // 更新进度条
          onProgress({ percent: percents }, file)
        },
        cancelToken: source.token
      }
      let res = await mirrorManageApi.uploadFile(
        { file },
        {
          ...config,
          headers: {
            'Content-Type': 'multipart/form-data',
            'hide-message': 'true'
          }
        }
      )

      formState.value.dockerFileUrlSign = res.data
      onSuccess(file)
      formRef.value?.validateFields('dockerFileUrlSign')
    } catch (error: any) {
      file.response = error.message
      onError(file, error?.message)
      formState.value.dockerFileUrlSign = ''
    }
  }

  // 删除
  const onRemove = () => {
    formState.value.dockerFileUrlSign = ''
    fileList.value = []
    source?.cancel()
    formRef.value?.validateFields('dockerFileUrlSign')
  }

  const confirmLoading = ref(false)
  const onOk = async () => {
    await formRef.value?.validateFields()
    confirmLoading.value = true
    if (formState.value.dockerFileUrlSign === 'uploading') {
      message.error('请等待文件上传后再提交')
    }
    try {
      const handleApi = formState.value.id ? mirrorManageApi.editMirror : mirrorManageApi.addMirror
      let params = cloneDeep(formState.value)
      if (params.repositoryId === 'open') {
        params.repositoryId = ''
      }
      if (params.buildType === 1) {
        params.repositoryName = repositoryOptions.value.filter(item => item.value === params.repositoryId)[0]?.label
      }
      await handleApi(params, { isAddUid: true })
      open.value = false
      message.success(`${formState.value.id ? '编辑' : '创建'}成功`)
      props.afterCloseFn()
      confirmLoading.value = false
    } catch (error) {
      confirmLoading.value = false
    }
  }

  const reset = () => {
    formRef.value?.resetFields()
    fileList.value = []
    repositoryOptions.value = [{ label: '公开仓库', value: 'open' }]
    formState.value = {
      id: '',
      imageName: '',
      buildType: 1,
      repositoryId: 'open',
      frame: '',
      description: ''
    }
  }

  // 获取仓库列表
  const repositoryOptions = ref<any[]>([{ label: '公开仓库', value: 'open' }])
  const { loading: repositoryLoading, runAsync: getRepositoryOptions } = useRequest<ResponseData<RepositoryType[]>>(
    mirrorManageApi.getRepositoryOptions,
    {
      onSuccess: ({ data }) => {
        console.log('数据', data)
        let repositoryData = data.map((item: RepositoryType) => ({ label: item.repositoryName, value: item.id }))
        repositoryOptions.value.push(...repositoryData)
        console.log('数据666', repositoryOptions.value)
      }
    }
  )

  defineExpose({
    open: (form?: FormState) => {
      reset()
      if (form) {
        Object.assign(formState.value, form)
      }
      open.value = true
      getRepositoryOptions()
    }
  })
</script>

<style lang="less" scoped>
  .upload-btn {
    padding: 0;
    color: rgba(0, 156, 248, 1);
  }
</style>
